home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / generic / doexec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.1 KB  |  587 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17.  
  18. #include <gl.h>
  19. #include <device.h>
  20. #include <stdio.h>
  21. #include <unistd.h>
  22. #include <bstring.h>
  23. #include <errno.h>
  24. #include <assert.h>
  25. #include <sys/types.h>
  26. #include <sys/socket.h>
  27. #include <sys/signal.h>
  28. #include <sys/fcntl.h>
  29. #include <sys/errno.h>
  30. #include <sys/stat.h>
  31. #include <netinet/in.h>
  32. #include <sys/time.h>
  33. #include "gizmo.h"
  34. #include "generic.h"
  35. #ifdef __cplusplus
  36. #include <osfcn.h>
  37. #include <stdarg.h>
  38. #else
  39. #include <varargs.h>
  40. #endif
  41.  
  42. #define CQLEN 400
  43.  
  44. int    gd;
  45. gizmo_t *gizmoptr;
  46. gizmo_t *getgp(long);
  47.  
  48. /*    gd = qgetfd();    XXX */
  49.  
  50.  
  51. gizmo_t        mastergizmo = {
  52.     "gizmos/mastergizmo",          /* name */
  53.     0,                 /* fd */
  54.     0,                 /* pid */ 
  55.     300,         /* llx */ 
  56.     300,         /* lly */ 
  57.     0,                 /* xsize */ 
  58.     0,                 /* ysize */ 
  59.     0,                 /* state */ 
  60.     0,                 /* initme */ 
  61.     0,                 /* killme */ 
  62.     0,                 /* next */
  63. };
  64.  
  65. gizmo_t        browsegizmo = {
  66.     "/usr/lib/showcase/browsegizmo",          /* name */
  67.     0,                 /* fd */
  68.     0,                 /* pid */ 
  69.     0,                 /* llx */ 
  70.     0,                 /* lly */ 
  71.     0,                 /* xsize */ 
  72.     0,                 /* ysize */ 
  73.     0,                 /* state */ 
  74.     0,                 /* initme */ 
  75.     0,                 /* killme */ 
  76.     0,                 /* next */
  77.  
  78. };
  79.  
  80. void senddevstring(gizmo_t *gp, long dev, char *str)
  81. {
  82.     long    buf[210], i = 1;
  83.  
  84.     if (gp->fd == 0) return;
  85.     buf[0] = dev;
  86.     while (*str) {
  87.     buf[i++] = *str++;
  88.     }
  89.     buf[i++] = 0;
  90.     if(write(gp->fd, buf, (unsigned int)(i*sizeof(long))) < 0) {
  91.     perror("writing stream message");
  92.     if (entries.exit) entries.exit();
  93.     exit(1);
  94.     }
  95. }
  96.  
  97. void senddev(gizmo_t *gp, long dev)
  98. {
  99.     if (gp->fd == 0) return;
  100.     if (write(gp->fd, &dev, sizeof(dev)) < 0)  {
  101.     perror("writing stream message");
  102.     if (entries.exit) entries.exit();
  103.     exit(1);
  104.     }
  105. }
  106.  
  107. void senddevval(gizmo_t *gp, long dev, long val)
  108. {
  109.     long buf[2];
  110.     
  111.     if (gp->fd == 0) return;
  112.     buf[0] = dev;
  113.     buf[1] = val;
  114.     if (write(gp->fd, buf, sizeof(buf)) < 0)  {
  115.     perror("writing stream message");
  116.     if (entries.exit) entries.exit();
  117.     exit(1);
  118.     }
  119. }
  120.  
  121. long readbuf(int fd, char *p, int totbytes)
  122. {
  123.     int nbytes, n;
  124.  
  125.     nbytes = 0;
  126.     while (nbytes < totbytes) {
  127.     if ( (n=read(fd,p+nbytes,totbytes-nbytes)) < 0) {
  128.         if (errno == EINTR) continue;
  129.         perror("Read failure");
  130.         return -1;
  131.     }
  132.     if (n == 0)
  133.         break;
  134.     nbytes += n;
  135.     }
  136.     return nbytes;
  137. }
  138.  
  139. long readlongfromsocket(gizmo_t *gp)
  140. {
  141.     long val;
  142.  
  143.     if (gp->fd == 0) return 0;
  144.     if (readbuf(gp->fd,(char *)&val,sizeof(val)) < 0) {
  145.         (void)fprintf(stderr,"unknown data from socket\n");
  146.     if (entries.exit) entries.exit();
  147.         exit(0);
  148.     }
  149.     return val;
  150. }
  151.  
  152. void sendstringtogizmo(gizmo_t *gp, long type, char *s)
  153. {
  154.     long    buf[210], i = 2;
  155.  
  156.     buf[0] = type;
  157.     buf[1] = -1;
  158.  
  159.     if (!s)
  160.     goto lastwrite;
  161.     do {
  162.     buf[i++] = type;
  163.     buf[i++] = *s++;
  164.     } while (*s);
  165. lastwrite:
  166.     if (write(gp->fd, buf, (unsigned int)(i*sizeof(long))) < 0) {
  167.     if (gp && gp->pid) (void)kill(gp->pid,SIGTERM);
  168.     }
  169. }
  170.  
  171.  
  172. /* The first item in the arg list must be a pointer to gizmo_t. The rest are
  173.  * gizmo specific.
  174.  */
  175.  
  176. /*VARARGS*/
  177. #ifdef __cplusplus
  178. void doexec(gizmo_t *gizptr ...)
  179. #else
  180. void doexec(va_alist)
  181. va_dcl
  182. #endif
  183. {
  184.     struct    sockaddr_in saddr;
  185.     int        len, sock1, child, fd;
  186.     char    charportnum[100], *gargv[20];
  187.     struct    stat statbuf;
  188.     va_list    ap;
  189.     gizmo_t     *gp;
  190.     long        argno;
  191.  
  192.  
  193. #ifdef __cplusplus
  194.     va_start(ap, gizptr);
  195.     gp = gizptr;
  196. #else
  197.     va_start(ap);
  198.     gp = (gizmo_t *)va_arg(ap, gizmo_t *);
  199. #endif
  200.     if (-1 == stat(gp->name,&statbuf)) {
  201.     perror("stat error");
  202.     if (entries.exit) entries.exit();
  203.     exit(1);
  204.     }
  205.     gd = qgetfd();
  206.  
  207.     sock1 = socket(AF_INET, SOCK_STREAM, 0);
  208.     if(sock1 < 0) {
  209.     perror("error opening socket");
  210.     if (entries.exit) entries.exit();
  211.     exit(1);
  212.     }
  213.  
  214.     /* Create name for parent socket on local machine. */
  215.  
  216.     saddr.sin_family = AF_INET;
  217.     saddr.sin_addr.s_addr = INADDR_ANY;
  218.     saddr.sin_port = 0;
  219.     if(bind(sock1, &saddr, sizeof(saddr))) {
  220.     perror("binding parent socket");
  221.     (void)close(sock1);
  222.     if (entries.exit) entries.exit();
  223.     exit(1);
  224.     }
  225.  
  226.     /* Find out port number assigned to parent socket. */
  227.  
  228.     len = sizeof(saddr);
  229.     if(getsockname(sock1, &saddr, &len)) {
  230.     perror("getting parent socket name");
  231.     (void)close(sock1);
  232.     if (entries.exit) entries.exit();
  233.     exit(1);
  234.     }
  235.  
  236.     (void)listen(sock1, 1 /* max size of queue of waiting connectors */);
  237.     child = fork();
  238.     if(child) {
  239. retry:
  240.     fd = accept(sock1, 0, 0);
  241.     if(fd == -1) {
  242.         if (errno == EINTR)
  243.         goto retry;
  244.         (void)fprintf(stderr, "Failed to open gizmo.\nError %d", errno);
  245.         (void)kill(child,SIGKILL);
  246.         if (entries.exit) entries.exit();
  247.         exit(1);
  248.     }
  249.     gp->fd = fd;
  250.     gp->pid = child;
  251.     if (gizmoptr == 0) {
  252.         gizmoptr = gp;
  253.         gp->next = 0;
  254.     } else {
  255.         gp->next = gizmoptr;
  256.         gizmoptr = gp;
  257.     }
  258.     gp->state = GIZMOSTATE_OPEN;
  259.     (void)close(sock1);
  260.     } else {
  261.     (void)close(sock1);
  262.     (void)sprintf(charportnum, "%d", (int)ntohs(saddr.sin_port));
  263.     gargv[0] = gp->name;
  264.     gargv[1] = charportnum;
  265.     for (argno = 2; gargv[argno] = (char *)va_arg(ap, char *); argno++) {
  266.         /*printf("%s\n", gargv[argno]);*/
  267.         ;
  268.     }
  269.     (void)execvp(gp->name, gargv);
  270.     perror("exec failed");
  271.     if (entries.exit) entries.exit();
  272.     exit(1);
  273.     }
  274.     va_end();
  275. }
  276.  
  277. /*
  278.  * find the gizmo with the correct pid.  We have gotten a signal that it 
  279.  * died.
  280.  */
  281.  
  282. static void gizmofuneral(long deadbaby)
  283. {
  284.     gizmo_t *gp, **prev;
  285.  
  286.     prev = &gizmoptr;
  287.     for (gp = gizmoptr; gp; gp = gp->next) {
  288.     if (gp->pid == deadbaby) {
  289.         /* fix up the gizmo stuff for that gizmo */
  290.         if (gp->killme)
  291.             (*gp->killme)();
  292.         gp->state = GIZMOSTATE_CLOSED;
  293.         gp->pid = 0;
  294.         gp->fd = 0;
  295.         *prev = gp->next;
  296.         return;
  297.     }
  298.     prev = &gp->next;
  299.     }
  300. }
  301.  
  302. void murdergizmos()
  303. {
  304.     gizmo_t *gp;
  305.  
  306.     for (gp = gizmoptr; gp; gp = gp->next) {
  307.     (void)kill(gp->pid,SIGTERM);
  308.     (void)kill(gp->pid,SIGTERM);
  309.     (void)kill(gp->pid,SIGTERM);
  310.     (void)kill(gp->pid,SIGTERM);
  311.     /* There!  That ought to kill it fer sure! */
  312.     }
  313. }
  314.  
  315. void quitgizmo(long val)
  316. {
  317.     gizmo_t *gp;
  318.     
  319.     gp = getgp(val);
  320.     if(gp && gp->pid) {
  321.         (void)kill(gp->pid,SIGTERM); 
  322.         gizmofuneral(gp->pid);
  323.     }
  324. }
  325.  
  326. void freezeallgizmos()
  327. {
  328.     gizmo_t *gp;
  329.  
  330.     for (gp = gizmoptr; gp; gp = gp->next) {
  331.     senddev(gp,WINFREEZE);
  332.     }
  333. }
  334.  
  335. void thawallgizmos()
  336. {
  337.     gizmo_t *gp;
  338.  
  339.     for (gp = gizmoptr; gp; gp = gp->next) {
  340.     senddev(gp,WINTHAW);
  341.     }
  342. }
  343.  
  344. /* Event reception *********************************************************/
  345.  
  346. static long cqdev[CQLEN], cqval[CQLEN];
  347. static long cqhead = 0, cqtail = 0;
  348.  
  349. void cookedqenter(long dev, long val)
  350. {
  351.     cqdev[cqhead] = dev; cqval[cqhead] = val;
  352.     cqhead++;
  353.     if (cqhead == CQLEN) cqhead = 0;
  354.     assert(cqhead != cqtail);
  355. }
  356.  
  357. long getqevent(long *val, long *dev)
  358. {
  359.     short    sval;
  360.  
  361.     if (qtest() == 0) {*dev = 0; return 0; }
  362.     *dev = qread(&sval);
  363.     *val = sval;
  364.     return 1;
  365. }
  366.  
  367. /* rawqread() is like qread() except that it deals in longs instead
  368.  * of shorts,  and it merges together commands that come from the
  369.  * event queue and any gizmos that happen to be running.  If you're
  370.  * not using the graphics queue, this has got to be re-written to
  371.  * merge inputs from the appropriate places.
  372.  */
  373.  
  374. int rawqread(long *val)
  375. {
  376.     long    dev, n;
  377.     fd_set    fdset;
  378.     long    buf[2];
  379.     struct timeval    timeout, *tp = &timeout;
  380.     gizmo_t     *gp;
  381.  
  382.     while(1) {
  383.         if (cqhead != cqtail) {
  384.             *val = cqval[cqtail];
  385.             dev = cqdev[cqtail];
  386.             cqtail++;
  387.             if (cqtail == CQLEN) cqtail = 0;
  388.             return dev;
  389.     }
  390. tryagain:
  391.     if (getqevent(val, &dev))
  392.         return dev;
  393.     FD_ZERO(&fdset);
  394.     FD_SET(gd, &fdset);
  395.     for (gp = gizmoptr; gp; gp = gp->next) {
  396.         FD_SET(gp->fd, &fdset); /* do this for all gizmos */
  397.     }        
  398.     tp = 0;
  399.     while ((n = select(FD_SETSIZE, &fdset, (fd_set *)0, (fd_set *)0, tp)) < 0) {
  400.         if (errno == EINTR)    {
  401.         goto tryagain;
  402.         }
  403.         perror("select");
  404.         (void)fprintf(stderr, "select error");
  405.     }
  406.     for (gp = gizmoptr; gp; gp = gp->next) {
  407.         if(FD_ISSET(gp->fd, &fdset)) { /* do this for all gizmos */
  408.         if((n = readbuf(gp->fd, (char *)buf, sizeof(buf))) < 0) {
  409.             perror("Error reading stream message");
  410.             (void)kill(gp->pid,SIGKILL);
  411.         }
  412.         if (n == 0) {
  413.             continue;
  414.         }
  415.         /* setmainwindow(); */
  416.         *val = buf[1];
  417.         return buf[0];
  418.         }
  419.     }
  420.     if(FD_ISSET(gd, &fdset)) {  /* grapics input queue non-empty */
  421.         (void)getqevent(val, &dev);
  422.         return dev;
  423.     }
  424.     }
  425. }
  426.  
  427. static long altkeydown()
  428. {
  429.     return (getbutton(LEFTALTKEY) || getbutton(RIGHTALTKEY));
  430. }
  431.  
  432. /* cookedqread() is the routine called by the application to get
  433.  * events.  It can do translations, interpret alt, ctrl, and shift
  434.  * keys, etc.
  435.  */
  436.  
  437. long cookedqread(long *val)
  438. {   
  439.     long dev;
  440.     
  441.     dev = rawqread(val);
  442.     if (dev == KEYBD && altkeydown()) {
  443.     switch (*val) {
  444.         case 'n':
  445.             return NEWCMD;
  446.         case 'o':
  447.             return OPENCMD;
  448.         case 's':
  449.             return SAVECMD;
  450.         case 'S':
  451.             return SAVEASCMD;
  452.         case 'p':
  453.             return PRINTCMD;
  454.         case 'q':
  455.             return QUITCMD;
  456.     }
  457.     }
  458.     return dev;    
  459. }
  460.  
  461. void centerovercursor(long *llx, long *urx, long *lly, long *ury, long width, long height)
  462. {
  463.     *llx = getvaluator(MOUSEX) - width/2;
  464.     *ury = getvaluator(MOUSEY) + height/2;
  465.     if (*llx + width > getgdesc(GD_XPMAX))
  466.         *llx = getgdesc(GD_XPMAX) - width -10;
  467.     if (*ury - height < 0)
  468.         *ury = height+10;
  469.     *lly = *ury - height;
  470.     *urx = *llx + width;
  471. }
  472.  
  473. /* Exec-ing and killing gizmos ***********************************************/
  474.  
  475. void opengizmo(long val)
  476. {
  477.     char    llx[10], lly[10];
  478.     gizmo_t *gp;
  479.     
  480.     gp = getgp(val);
  481.     if (gp->pid) return;    /* it is already open */
  482.     (void)sprintf(llx, "%d", (int)gp->llx);
  483.     (void)sprintf(lly, "%d", (int)gp->lly);
  484.     doexec(gp, "8", llx, lly, 0);
  485.     if (gp->pid) {
  486.         if (gp->initme)
  487.         (*gp->initme)();
  488.     else senddev(gp, GIZMOINITEND);
  489.     }
  490. }
  491.  
  492. gizmo_t *getgp(long val)
  493. {
  494.     switch(val) {
  495.     case GIZMO_MASTER: 
  496.         return &mastergizmo;
  497.     }
  498.     return 0;
  499. }
  500.  
  501. static void openbrowsegizmo(gizmo_t *gp, char *title, char *dir,
  502.                             char *buttonstring, char *accepttitle)
  503. {
  504.     char cx[10], cy[10];
  505.     long width = 340;
  506.     long height = 450;
  507.     long llx, lly, urx, ury;
  508.  
  509.     if (gp->state == GIZMOSTATE_OPEN) {
  510.     /* need to init x, y, title, dir and buttonstring too */
  511.         centerovercursor(&llx,  &urx, &lly, &ury, width, height);
  512.     senddevval(gp,GIZMOXORG ,llx);
  513.     senddevval(gp,GIZMOYORG,lly);
  514.     if (title) sendstringtogizmo(gp, TITLESTRDEV, title);
  515.     if (dir) sendstringtogizmo(gp, DIRNAMEDEV ,dir);
  516.     /* always send buttonstring to clear it if null */
  517.     sendstringtogizmo(gp, BUTTONSTRDEV ,buttonstring );
  518.     sendstringtogizmo(gp, ACCEPTSTRDEV ,accepttitle );
  519.     senddev(gp, REINITEND);
  520.     return;
  521.     }
  522.     centerovercursor(&llx, &urx, &lly, &ury, width, height);
  523.     (void)sprintf(cx, "%d", (int)llx);
  524.     (void)sprintf(cy, "%d", (int)lly);
  525.     doexec(gp, "0", cx, cy, title, dir, buttonstring, accepttitle, 0);
  526.     senddev(gp,GIZMOINITEND);
  527. }
  528.  
  529. extern void handleredraw();
  530.  
  531. /* This getfilename() fires up the showcase browse gizmo to collect a
  532.  * name.  Replace it with whatever you want.
  533.  */
  534.  
  535. long getfilename(char *title, 
  536.         char *filename, 
  537.         char *buttonstring, 
  538.         char *dir, 
  539.             char *acceptbuttitle, 
  540.             long (*filetype)(char *))
  541. {
  542.     long dev, val;
  543.     
  544.     *filename = 0;
  545.     openbrowsegizmo(&browsegizmo, title, dir, buttonstring, acceptbuttitle);
  546.     if (!browsegizmo.fd)
  547.     return -1;
  548.     while (1) {
  549.     dev = cookedqread(&val);
  550.     switch (dev) {
  551.         case CREATEDEV:
  552.         val = readlongfromsocket(&browsegizmo);
  553.         /* this means they want to create a new thing */
  554.         /* send FREEZE not ABORT, so process stays around */
  555.         senddev(&browsegizmo, WINFREEZE);
  556.         return 0;
  557.         case DIRNAMEDEV:
  558.         if (0 > readbuf(browsegizmo.fd, dir, (int)val)) {
  559.             perror("Error reading stream message");
  560.             (void)kill(browsegizmo.pid,SIGKILL);
  561.         }
  562.         break;
  563.         case FILENAMEDEV:
  564.         if (0 > readbuf(browsegizmo.fd, filename, (int)val)) {
  565.             perror("Error reading stream message");
  566.             (void)kill(browsegizmo.pid,SIGKILL);
  567.             *filename = 0;
  568.             return 0;
  569.         }
  570.         if (filetype && (!(*filetype)(filename))){
  571.             *filename = 0;
  572.             return getfilename(title, filename, buttonstring, dir, acceptbuttitle, filetype);
  573.         }
  574.         return 1;
  575.         case ABORT: /*  user chose CANCEL*/
  576.         *filename = 0;
  577.         return -1;
  578.         case REDRAW:
  579.         handleredraw();
  580.         break;
  581.         default:
  582.         senddev(&browsegizmo, POKEGIZMO);
  583.         break;
  584.     }
  585.     }
  586. }
  587.